﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace jsonar
{
	/// <summary>
	/// 区分大小写的JSON对象
	/// </summary>
	public sealed class Obj : Json, IEnumerable<KeyValuePair<string,Json>>
	{
		public readonly static Obj NullINSTANCE = null;
		//public readonly static Obj EmptyINSTANCE = new Obj();
		private readonly static int[] Primes = new int[] { 
			0x00000b, 0x000011, 0x000017, 0x00001d, 0x000025, 0x00002f, 0x00003b, 0x000047, 0x000059, 0x00006b,
			0x000083, 0x0000a3, 0x0000c5, 0x0000ef, 0x000125, 0x000161, 0x0001af, 0x000209, 0x000277, 0x0002f9,
			0x000397, 0x00044f, 0x00052f, 0x00063d, 0x00078b, 0x00091d, 0x000af1, 0x000d2b, 0x000fd1, 0x0012fd,
			0x0016cf, 0x001b65, 0x0020e3, 0x002777, 0x002f6f, 0x0038ff, 0x00446f, 0x00521f, 0x00628d, 0x007655,
			0x008e01, 0x00aa6b, 0x00cc89, 0x00f583, 0x0126a7, 0x01619b, 0x01a857, 0x01fd3b, 0x026315, 0x02dd67,
			0x03701b, 0x042023, 0x04f361, 0x05f0ed, 0x072125, 0x088e31, 0x0a443b, 0x0c51eb, 0x0ec8c1, 0x11bdbf,
			0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b, 0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89, 
			0x8ef6e7, 0xacfec1, 0xd80001, 0x1001fff, 0x123ede5, 0x1b00001
		};
		private static int ComputeCapacity(int capacity)
		{
			if (capacity <= 7) return 7;
			int start = 0; int end = 0;
			if (capacity <= 0x6b) end = 9;
			else if (capacity <= 0x2f9) { start = 10; end = 19; }
			else if (capacity <= 0x12fd) { start = 20; end = 29; }
			else if (capacity <= 0x7655) { start = 30; end = 39; }
			else if (capacity <= 0x2dd67) { start = 40; end = 49; }
			else if (capacity <= 0x11bdbf) { start = 50; end = 59; }
			else if (capacity <= 0x6dda89) { start = 60; end = 69; }
			else if (capacity <= 0x1b00001) { start = 70; end = Primes.Length - 1; }
			else return 0x1b00001;
			for (; end >= start; start++) { if (capacity <= Primes[start]) return Primes[start]; }
			return 0x1b00001;
		}

        #region 属性/字段
        public override int Count() { return this.count; }
        private int count;

        private int capacity;
        private int freelist;
        private int maxpos;
        private int[] buckets;
        private Field[] entries;
        #endregion

        #region 构造函数
		public Obj(int capacity = 0)
        {
			this.initialize(capacity);
        }
		private Obj() { }
		private void initialize(int capacity)
        {
			this.count = 0;
			this.maxpos = 0;
			this.freelist = 0;
			this.capacity = ComputeCapacity(capacity + 1);
			this.buckets = new int[this.capacity];
			this.entries = new Field[this.capacity];
        }
        private void resize()
        {
			int cap = ComputeCapacity(this.count << 1);
			int[] buckes = new int[cap];
			Field[] entrys = new Field[cap]; Array.Copy(this.entries, 1, entrys, 1, this.maxpos);
			int index = 0;
			for (int i = 1; i <= this.maxpos; i++)
			{
				if (entrys[i].Hash < 0) continue;
				index = entrys[i].Hash % cap;
				entrys[i].Next = buckes[index]; buckes[index] = i;
			}
			this.capacity = cap;
			this.entries = entrys;
			this.buckets = buckes;
        }
        #endregion

		#region 方法

		public override Obj getValue(Obj dft) { return this; }

		private void add(string name, Json json)
		{
			if (name == null || entries == null) return;
			name = name.Trim(); if (name.Length < 1) return;
			if (json == null) json = Null.INSTANCE;
			int hash = name.GetHashCode() & 0x7fffffff; int index = hash % this.capacity;
			for (int i = this.buckets[index]; i > 0; i = this.entries[i].Next)
			{
				if (this.entries[i].Hash == hash && name == this.entries[i].Name)
				{
					this.entries[i].Name = name;
					this.entries[i].Value = json;
					return;
				}
			}
			int idx = 0;
			if (this.freelist > 0) { idx = this.freelist; this.freelist = this.entries[idx].Next; }
			else if ((this.maxpos + 1) >= this.capacity) { this.resize(); idx = ++this.maxpos; index = hash % this.capacity; }
			else idx = ++this.maxpos;

			this.entries[idx].Name = name;
			this.entries[idx].Hash = hash;
			this.entries[idx].Value = json;
			this.entries[idx].Next = this.buckets[index];
			this.buckets[index] = idx;
			this.count++;
		}

		/// <summary>
		/// 添加
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="name"></param>
		/// <param name="value"></param>
		/// <param name="replace">存在时替换</param>
		/// <returns>this</returns>
		public Obj Add<T>(string name, T value, bool replace = true) 
		{
			if (replace || this.Find(name) < 1) this.add(name, GetJson(value)); 
			return this; 
		}
		/// <summary>
		/// 添加
		/// </summary>
		/// <param name="name"></param>
		/// <param name="value"></param>
		/// <param name="deep">对object的解析深度，0不解析</param>
		/// <param name="replace">存在时替换</param>
		/// <returns>this</returns>
		public Obj Add(string name, IEnumerable value, int deep = 0, bool replace = true) 
		{ 
			if (replace || this.Find(name) < 1) this.add(name, GetJson(value, deep)); 
			return this; 
		}
		/// <summary>
		/// 添加
		/// </summary>
		/// <param name="name"></param>
		/// <param name="value"></param>
		/// <param name="deep">对object的解析深度，0不解析</param>
		/// <param name="replace">存在时替换</param>
		/// <returns>this</returns>
		public Obj Add(string name, object value, int deep = 0, bool replace = true) 
		{
			if (replace || this.Find(name) < 1) this.add(name, GetJson(value, deep)); 
			return this; 
		}
		/// <summary>
		/// 添加多项
		/// </summary>
		/// <param name="items">
		/// Array：每一项，名称就是序号
		/// IEnumerable：每一项
		/// object：全部公共属性和字段
		/// other：忽略
		/// </param>
		/// <param name="deep">对object的解析深度，0不解析</param>
		/// <param name="replace">存在时替换</param>
		/// <returns></returns>
		public Obj Add(object items, int deep = 0, bool replace = true) 
		{
			Json jb = GetJson(items, deep);
			if (jb is Obj)
			{
				Obj jo = jb as Obj;
				foreach (var kv in jo) { if (replace || this.Find(kv.Key) < 1) this.add(kv.Key, kv.Value); }
			}
			else if (jb is Arr)
			{
				Arr ja = jb as Arr; int i = 0;
				foreach (var j in ja) { if (replace || this.Find(i.ToString()) < 1) this.add((i++).ToString(), j); }
			}
			return this;
		}
		/// <summary>
		/// 获取已有或添加一个空Obj
		/// </summary>
		/// <param name="name"></param>
		/// <param name="capacity">新Obj的初始容量</param>
		/// <param name="replace">存在时替换</param>
		/// <returns>新增或找到的Obj</returns>
		public Obj AddObj(string name, int capacity = 0, bool replace = true) {
			Obj obj = null; int idx = 0;
			if (!replace && (idx = this.Find(name)) > 0) obj = this.entries[idx].Value.getValue(obj);
			if(obj == null){ obj = new Obj(capacity); this.add(name, obj); }
			return obj; 
		}
		/// <summary>
		/// 获取已有或添加一个空Arr
		/// </summary>
		/// <param name="name"></param>
		/// <param name="capacity">新Arr的初始容量</param>
		/// <param name="replace">存在时替换</param>
		/// <returns>新增或找到的Arr</returns>
		public Arr AddArr(string name, int capacity = 0, bool replace = true) {
			Arr arr = null; int idx = 0;
			if (!replace && (idx = this.Find(name)) > 0) arr = this.entries[idx].Value.getValue(arr);
			if (arr == null) { arr = new Arr(capacity); this.add(name, arr); }
			return arr; 
		}

		/// <summary>
		/// 删除
		/// </summary>
		/// <param name="name"></param>
		/// <returns>this</returns>
		public Obj Remove(string name)
        {
            if (name == null || this.count < 1) return this;
            int hash = name.GetHashCode() & 0x7fffffff; int index = hash % this.capacity;
            int pre = -1;
            for (int i = this.buckets[index]; i > 0; i = this.entries[i].Next)
            {
                if (this.entries[i].Hash == hash && name == this.entries[i].Name)
				{
					if (pre < 0) this.buckets[index] = this.entries[i].Next;
					else this.entries[pre].Next = this.entries[i].Next;
                    this.entries[i].Hash = -1;
					this.entries[i].Name = null;
                    this.entries[i].Value = null;
                    this.entries[i].Next = this.freelist;
                    this.freelist = i;
                    this.count--;
                    return this;
                }
                pre = i;
            }
			return this;
        }

		public override bool hasChild() { return this.count > 0; }

		public override Json getChild(string name) 
		{
			int index = this.Find(name);
			if (index < 1) return Null.INSTANCE;
			return this.entries[index].Value;
		}

		public bool Contains(string name) { return  this.Find(name) > 0; }
		private int Find(string name)
		{
			if (name == null || this.count < 1) return -1;
			int hash = name.GetHashCode() & 0x7fffffff; int index = hash % this.capacity;
			for (int idx = this.buckets[index]; idx > 0; idx = this.entries[idx].Next)
			{
				if (this.entries[idx].Hash == hash && name == this.entries[idx].Name) return idx;
			}
			return -1;
		}

		public IEnumerator<KeyValuePair<string, Json>> GetEnumerator()
		{
			int idx = 1;
			while (idx <= this.maxpos)
			{
				if (this.entries[idx].Hash < 0) { idx++; continue; }
				yield return new KeyValuePair<string, Json>( this.entries[idx].Name,this.entries[idx++].Value);
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		public override string ToString()
		{
			if (this.count < 1) return "null";
			System.Text.StringBuilder sb = new System.Text.StringBuilder(100);
			sb.Append("{");
			int idx = -1;
			while (++idx <= this.maxpos)
			{
				if (this.entries[idx].Hash < 0) continue;
				if (sb.Length > 1) sb.Append(",");
				sb.Append(this.entries[idx].ToString());
			}
			sb.Append("}");
			return sb.ToString();
		}
		public override string toHtml()
		{
			if (this.count < 1) return "null";
			System.Text.StringBuilder sb = new System.Text.StringBuilder(100);
			sb.Append("<div class=\"JO\">{");
			int idx = -1;
			while (++idx <= this.maxpos)
			{
				if (this.entries[idx].Hash < 0) continue;
				if (sb.Length > 20)
				{
					sb.Append(",");
					sb.Append("<br/>");
				}
				sb.Append(this.entries[idx].ToHtml());
			}
			sb.Append("}</div>");
			return sb.ToString();
		}
        #endregion
	}
}
